package orbit

import (
	"gddgame.cc/galaxy/asteroid"
	"gddgame.cc/galaxy/asteroid/cluster"
	"gddgame.cc/galaxy/binocle"
	"gddgame.cc/galaxy/binocle/logic"
	"gddgame.cc/galaxy/common/feature/orbit"
	"gddgame.cc/galaxy/satellite/formula/comet"
	"gddgame.cc/galaxy/server/composer"
	"gddgame.cc/galaxy/server/web"
	"gddgame.cc/galaxy/utils/serialize"

	"gddgame.cc/galaxy/utils/def"
)

const (
	_ comet.DE = iota
	Subscribe
	UnSubscribe
	Publish
)

type PublishMessage struct {
	Topic   string
	Message string
}

type chatChannel struct {
	builder composer.Builder
	cloud   logic.Cloud
}

func (channel *chatChannel) initRoom(r *asteroid.Room) {
	r.Filter(Publish, func(message asteroid.Message, member def.Member) {
		socket := member.(*comet.Socket)
		d, _ := message.Payload()
		socket.Send(Publish, d)
	})
	// 清理为空的房间
	r.OnLeave(func(from string) {
		if r.Members() == 0 {
			r.Close()
		}
	})
}

func (channel *chatChannel) Connect(socket *comet.Socket) error {
	openId := ""
	var region *asteroid.Region

	socket.UpdateAuth(func(authority interface{}) {
		a := authority.(*auth)
		openId = a.openId
		region = channel.cloud.RegionWith(a, "chat")
	})
	socket.Dispatch(func(event comet.DE, packet comet.Packet) {
		if region == nil {
			return
		}
		switch event {
		case Subscribe:
			// topic
			b := packet.ReadBytes()
			rr, ok := region.OpenRoom(string(b))
			if !ok {
				channel.initRoom(rr)
			}
			err := socket.Add(rr)
			if err != nil {
				socket.SendError(err)
			} else {
				socket.Send(Subscribe, b)
			}
		case UnSubscribe:
			// topic
			b := packet.ReadBytes()
			rr, ok := region.OpenRoom(string(b))
			if !ok {
				channel.initRoom(rr)
			}
			err := socket.Delete(rr)
			if err != nil {
				socket.SendError(err)
			} else {
				//fmt.Println(b)
				socket.Send(UnSubscribe, b)
			}
		case Publish:
			// topic, message, openId
			b := serialize.GetBag()
			if err := b.Unmarshal(packet.ReadBytes()); err != nil {
				return
			}
			topic := b.ReadString(0)
			b.Push(openId)
			region.Broadcast(topic).Origin(socket).Data(b).Send(Publish)
			b.Release()
		}
	})
	socket.Disconnected(func(reason string) {

	})
	return nil
}

func (channel *chatChannel) Disconnect(socket *comet.Socket, reason string) error {
	return nil
}

/*
 聊天室逻辑
*/
func ChatHandler(builder composer.Builder, config *Config, env *orbit.Environment) comet.Interface {
	var agent binocle.Service
	builder.Factory("agent", &agent)
	c := &chatChannel{
		builder: builder,
		cloud:   agent,
	}

	return c
}

func ChatAppHandler(builder composer.Builder, router web.Router, config *Config) {
	var agent binocle.Service
	builder.Factory("agent", &agent)
	agent.MountNode(func(node cluster.Node) {

	})
}

func ChatManageHandler(builder composer.Builder, router web.Router, config *Config) {
	//s := builder.Feature("system")
	//s.MountNode(func(node cluster.Node) {
	//
	//})

	router.Get("/topic")
}
